package com.info.zhiduoduo.core.service.impl;

import com.baomidou.mybatisplus.mapper.Condition;
import com.google.common.collect.Lists;
import com.info.zhiduoduo.common.constants.Constants;
import com.info.zhiduoduo.common.constants.partner.BrokerageSettleType;
import com.info.zhiduoduo.common.constants.partner.PartnerBrokerageState;
import com.info.zhiduoduo.common.constants.partner.PartnerBrokerageType;
import com.info.zhiduoduo.common.constants.partner.PartnerCooperatorType;
import com.info.zhiduoduo.common.constants.partner.PartnerCrowdsourceCostState;
import com.info.zhiduoduo.common.constants.project.ProjectType;
import com.info.zhiduoduo.common.utils.NumberUtil;
import com.info.zhiduoduo.common.utils.RandomUtil;
import com.info.zhiduoduo.common.utils.StringUtil;
import com.info.zhiduoduo.core.service.CoreBrokerageService;
import com.info.zhiduoduo.core.service.WxPartnerMessageService;
import com.info.zhiduoduo.repository.dto.maker.StudioDetailDto;
import com.info.zhiduoduo.repository.dto.partner.PartnerDetailDto;
import com.info.zhiduoduo.repository.dto.partner.PartnerSubDto;
import com.info.zhiduoduo.repository.entity.company.CompanyProject;
import com.info.zhiduoduo.repository.entity.crowdsource.CrowdsourceProject;
import com.info.zhiduoduo.repository.entity.crowdsource.CrowdsourceTradeRecord;
import com.info.zhiduoduo.repository.entity.entrustmentproject.EntrustmentProject;
import com.info.zhiduoduo.repository.entity.maker.MakerStudio;
import com.info.zhiduoduo.repository.entity.partner.PartnerAccountflow;
import com.info.zhiduoduo.repository.entity.partner.PartnerBrokerage;
import com.info.zhiduoduo.repository.entity.partner.PartnerCompany;
import com.info.zhiduoduo.repository.entity.partner.PartnerMaker;
import com.info.zhiduoduo.repository.entity.taxer.TaxerInvoice;
import com.info.zhiduoduo.repository.entity.taxer.TaxerPayment;
import com.info.zhiduoduo.repository.mapper.maker.MakerStudioMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerBrokerageMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerCompanyMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerMakerMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerMonthlyCrowdCostMapper;
import com.info.zhiduoduo.repository.mapper.partner.PartnerSubMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class CoreBrokerageServiceImpl implements CoreBrokerageService {

	@Resource
	PartnerCompanyMapper partnerCompanyMapper;
	@Resource
	PartnerBrokerageMapper partnerBrokerageMapper;
	@Resource
	PartnerSubMapper partnerSubMapper;
	@Resource
	PartnerMapper partnerMapper;
	@Resource
	MakerStudioMapper makerStudioMapper;
	@Resource
	PartnerMakerMapper partnerMakerMapper;
	@Resource
	PartnerMonthlyCrowdCostMapper partnerMonthlyCrowdCostMapper;

	@Autowired
	WxPartnerMessageService wxPartnerMessageService;

	@Override
	public void prepareProjectBrokerage(int compid, int userid, int projectId, int projectType) {
		if (ProjectType.isZhiduoduoProject(projectType) && userid > 0) {
			// 只有创客开通了计算分佣的功能,才会确认项目的合伙人
			MakerStudio studio = new MakerStudio().selectById(userid);
			if (!NumberUtil.equals(studio.getBrokerageComputeState(), Constants.TRUE)) return;
		}

		//项目的合伙人确定
		int cooperatorType = PartnerCooperatorType.getByProjectType(projectType);
		if (cooperatorType == PartnerCooperatorType.MAKER) {
			// 创客合伙人
			List<PartnerMaker> validList = Lists.newArrayList();
			validList.addAll(partnerMakerMapper.getValidList(userid, PartnerBrokerageType.BASIC));
			validList.addAll(partnerMakerMapper.getValidList(userid, PartnerBrokerageType.PROJECT));

			validList.forEach(partner -> {
				log.info("发布项目：创客-{} 关联的partner-{}", userid, partner.getPartnerid());
				PartnerBrokerage pb = new PartnerBrokerage().setBrokerageno(RandomUtil.createRandomNo("PB", ""))
						.setProjectid(projectId)
						.setProjectType(projectType)
						.setCompid(compid)
						.setUserid(userid)
						.setCooperatorType(PartnerCooperatorType.MAKER)
						.setPartnerid(partner.getPartnerid())
						.setPartnerType(partner.getType())
						.setSettleType(partner.getSettleType())
						.setProjectno("P" + StringUtil.toFixedLengthNum(projectId, 9))
						.setRatio(partner.getRatio());
				pb.insert();
			});

		} else if (cooperatorType == PartnerCooperatorType.COMPANY) {
			// 企业合伙人
			List<PartnerCompany> validList = Lists.newArrayList();
			if (ProjectType.isZhiduoduoProject(projectType)) {
				validList.addAll(partnerCompanyMapper.getValidList(compid, PartnerBrokerageType.BASIC));
				validList.addAll(partnerCompanyMapper.getValidList(compid, PartnerBrokerageType.PROJECT));
			} else if (ProjectType.isCrowdsourceProject(projectType)) {
				validList.addAll(partnerCompanyMapper.getValidList(compid, PartnerBrokerageType.CROWDSOURCE));
			}

			validList.forEach(partner -> {
				log.info("发布项目：企业-{}关联的partner-{}", compid, partner.getPartnerid());
				PartnerBrokerage pb = new PartnerBrokerage().setBrokerageno(RandomUtil.createRandomNo("PB", ""))
						.setProjectid(projectId)
						.setProjectType(projectType)
						.setCompid(compid)
						.setUserid(userid)
						.setCooperatorType(PartnerCooperatorType.COMPANY)
						.setPartnerid(partner.getPartnerid())
						.setPartnerType(partner.getType())
						.setSettleType(partner.getSettleType())
						.setProjectno("P" + StringUtil.toFixedLengthNum(projectId, 9))
						.setRatio(partner.getRatio());
				pb.insert();
			});
		}
	}

	@Override
	public void handleZhiduoduoProjectPartnerBrokerage(CompanyProject project, int tradeid, String tradeno) {
		if (project == null) return;

		List<PartnerBrokerage> brokerageList = partnerBrokerageMapper.getZhiduoduoProjectBrokerageList(project.getProjectid(), ProjectType.ZHIDUODUO, 0);
		//2020.3.1 检查这些合伙人是否有上级合伙人,设置二级分佣
		addSubPartnerBrokerageList(brokerageList, project.getCompid(), project.getUserid(), project.getProjectid(), ProjectType.ZHIDUODUO);

		brokerageList.forEach(partnerBrokerage -> {
			Double ratio = partnerBrokerage.getRatio();
			if (ratio == null) return;

			//创客服务费是1%的，不记基本服务费的佣金
			Integer partnerType = partnerBrokerage.getPartnerType();
			if ((project.getProjectBaseServiceRate() == null || project.getProjectBaseServiceRate() <= 0.01d) && partnerType == PartnerBrokerageType.BASIC) {
				//如果佣金表中有存在记录，则删除
				new PartnerBrokerage().delete(
						Condition.create().eq("projectid", project.getProjectid()).eq("partnerid", partnerBrokerage.getPartnerid()).eq("partner_type", PartnerBrokerageType.BASIC));
				return;
			}

			BigDecimal dealamount = project.getProjectdealamount();
			BigDecimal brokerage = dealamount.multiply(BigDecimal.valueOf(ratio));
			partnerBrokerage.setBrokerage(brokerage)
					.setProjectdealamount(dealamount)
					.setProjectservicecharge(project.getProjectservicecharge())
					.setProjecttaxfee(project.getProjecttaxfee())
					.setTradeid(tradeid)
					.setTradeno(tradeno)
					.setState(PartnerBrokerageState.SETTLED);

			if (partnerBrokerage.updateById()) {
				// 记录合伙人账户流水并微信通知
				recordPartnerAccountFlowAndNotice(partnerBrokerage, project.getProjectname());
			}
		});

	}

	@Override
	public void handleCrowdsourceProjectPartnerBrokerage(CrowdsourceTradeRecord tradeRecord, CrowdsourceProject project) {
		List<PartnerBrokerage> brokerageList = partnerBrokerageMapper.getCrowdsourceProjectBrokerageList(project.getProjectid(), ProjectType.CROWDSOURCE, PartnerBrokerageType.CROWDSOURCE);
		// 2020.3.1 检查这些合伙人是否有上级合伙人,设置二级分佣
		addSubPartnerBrokerageList(brokerageList, project.getCompid(), 0, project.getProjectid(), ProjectType.CROWDSOURCE);

		brokerageList.forEach(partnerBrokerage -> {
			Double ratio = partnerBrokerage.getRatio();
			if (ratio == null) return;

			Integer batchId = null;
			String batchNo = null;
			if (tradeRecord != null) {
				batchId = tradeRecord.getBatchId();
				batchNo = tradeRecord.getBatchNo();
			}

			// 2021.8.6 计算的时候改成按交易开票金额计算佣金，佣金=开票金额*比例
			BigDecimal invoiceAmount = project.getProjectTotalInvoiceAmount();
			BigDecimal brokerage = invoiceAmount.multiply(BigDecimal.valueOf(ratio));
			// 结算类型是手动销账类型,则先记录为0
			if (partnerBrokerage.getSettleType() == BrokerageSettleType.MANUAL) {
				brokerage = BigDecimal.ZERO;
			}
			partnerBrokerage.setBrokerage(brokerage)
					.setProjectdealamount(invoiceAmount)
					.setProjectservicecharge(project.getProjectTotalServiceCharge())
					.setProjecttaxfee(BigDecimal.ZERO)
					.setTradeid(batchId)
					.setTradeno(batchNo)
					.setState(PartnerBrokerageState.SETTLED);

			if (partnerBrokerage.updateById() && partnerBrokerage.getSettleType() != BrokerageSettleType.MANUAL) {
				// 记录合伙人账户流水并微信通知
				recordPartnerAccountFlowAndNotice(partnerBrokerage, project.getProjectName());
			}
		});
	}

	@Override
	public void handleMakerGrouponZhiduoduoProjectPartnerBrokerage(EntrustmentProject project) {
		List<PartnerBrokerage> brokerageList = partnerBrokerageMapper.getCrowdsourceProjectBrokerageList(project.getId(),
				project.getProjectType(), 0);
		// 2020.3.1 检查这些合伙人是否有上级合伙人,设置二级分佣
		addSubPartnerBrokerageList(brokerageList, project.getCompid(), 0, project.getId(), project.getProjectType());

		brokerageList.forEach(partnerBrokerage -> {
			Double ratio = partnerBrokerage.getRatio();
			if (ratio == null) return;

			// 2021.8.6 计算的时候改成按交易开票金额计算佣金，佣金=开票金额*比例
			BigDecimal invoiceAmount = project.getImportedTaxInclusiveAmount();
			BigDecimal brokerage = invoiceAmount.multiply(BigDecimal.valueOf(ratio));
			// 结算类型是手动销账类型,则先记录为0
			if (partnerBrokerage.getSettleType() == BrokerageSettleType.MANUAL) {
				brokerage = BigDecimal.ZERO;
			}
			partnerBrokerage.setBrokerage(brokerage)
					.setProjectdealamount(invoiceAmount)
					.setProjectservicecharge(BigDecimal.ZERO)
					.setProjecttaxfee(BigDecimal.ZERO)
					.setState(PartnerBrokerageState.SETTLED);

			if (partnerBrokerage.updateById() && partnerBrokerage.getSettleType() != BrokerageSettleType.MANUAL) {
				// 记录合伙人账户流水并微信通知
				recordPartnerAccountFlowAndNotice(partnerBrokerage, "创客团塾人项目");
			}
		});
	}

	@Override
	public void handleMakerGrouponCrowdsourceProjectPartnerBrokerage(EntrustmentProject project) {
		List<PartnerBrokerage> brokerageList = partnerBrokerageMapper.getCrowdsourceProjectBrokerageList(project.getId(), project.getProjectType(), PartnerBrokerageType.CROWDSOURCE);
		// 2020.3.1 检查这些合伙人是否有上级合伙人,设置二级分佣
		addSubPartnerBrokerageList(brokerageList, project.getCompid(), 0, project.getId(), project.getProjectType());

		brokerageList.forEach(partnerBrokerage -> {
			Double ratio = partnerBrokerage.getRatio();
			if (ratio == null) return;

			// 2021.8.6 计算的时候改成按交易开票金额计算佣金，佣金=开票金额*比例
			BigDecimal invoiceAmount = project.getProjectTotalInvoiceAmount();
			BigDecimal brokerage = invoiceAmount.multiply(BigDecimal.valueOf(ratio));
			// 结算类型是手动销账类型,则先记录为0
			if (partnerBrokerage.getSettleType() == BrokerageSettleType.MANUAL) {
				brokerage = BigDecimal.ZERO;
			}
			partnerBrokerage.setBrokerage(brokerage)
					.setProjectdealamount(invoiceAmount)
					.setProjectservicecharge(BigDecimal.ZERO)
					.setProjecttaxfee(BigDecimal.ZERO)
					.setState(PartnerBrokerageState.SETTLED);

			if (partnerBrokerage.updateById() && partnerBrokerage.getSettleType() != BrokerageSettleType.MANUAL) {
				// 记录合伙人账户流水并微信通知
				recordPartnerAccountFlowAndNotice(partnerBrokerage, "创客团智众包项目");
			}
		});
	}

	@Override
	public void handleTaxerInvoicePartnerBrokerage(TaxerPayment payment, TaxerInvoice invoice) {
		if (invoice == null) return;

		List<PartnerBrokerage> brokerageList = partnerBrokerageMapper.getTaxerInvoiceBrokerageList(invoice.getInvoiceid(), 0);

		//2020.3.1 检查这些合伙人是否有上级合伙人,设置二级分佣
		Integer userid = invoice.getUserid();
		addSubPartnerBrokerageList(brokerageList, userid, userid, invoice.getInvoiceid(), ProjectType.TAXER);

		brokerageList.forEach(partnerBrokerage -> {
			Double ratio = partnerBrokerage.getRatio();
			if (ratio == null) return;

			BigDecimal dealamount = invoice.getAmount();
			BigDecimal brokerage = dealamount.multiply(BigDecimal.valueOf(ratio));
			partnerBrokerage.setBrokerage(brokerage)
					.setProjectdealamount(dealamount)
					.setProjectservicecharge(invoice.getServiceCharge())
					.setProjecttaxfee(invoice.getTaxFee())
					.setTradeid(payment.getPayid())
					.setTradeno(payment.getPayno())
					.setState(PartnerBrokerageState.SETTLED);

			if (partnerBrokerage.updateById()) {
				// 记录合伙人账户流水并微信通知
				recordPartnerAccountFlowAndNotice(partnerBrokerage, invoice.getProjectname());
			}
		});
	}

	private void addSubPartnerBrokerageList(List<PartnerBrokerage> brokerageList, int compid, int userid, int projectid, int projectType) {

		List<PartnerBrokerage> subPartnerBrokerageList = brokerageList.stream()
				.map(brokerage -> partnerSubMapper.findUpPartnerBySubId(brokerage.getPartnerid()))
				.filter(Objects::nonNull)
				.collect(Collectors.groupingBy(PartnerSubDto::getPartnerid))
				.values()
				.stream()
				.map(list -> {
					if (list.size() == 1) {
						return list.get(0);
					} else {
						//A发展B和C，如果B和C发展了同一家企业，这时候A是只能拿一个分佣
						return list.stream().max(Comparator.comparing(PartnerSubDto::getRate)).orElse(null);
					}
				})
				.filter(Objects::nonNull)
				.map(partner -> {
					log.info("添加下级合伙人-{} 关联的上级partner-{}", partner.getSubPartnerid(), partner.getPartnerid());
					PartnerBrokerage pb = new PartnerBrokerage().setBrokerageno(RandomUtil.createRandomNo("PB", ""))
							.setProjectid(projectid)
							.setProjectType(projectType)
							.setCompid(compid)
							.setUserid(userid)
							.setCooperatorType(PartnerCooperatorType.getByProjectType(projectType))
							.setPartnerid(partner.getPartnerid())
							.setSubPartnerid(partner.getSubPartnerid())
							.setPartnerType(PartnerBrokerageType.SUB_PARTNER)
							.setSettleType(BrokerageSettleType.AUTO)
							.setProjectno("P" + StringUtil.toFixedLengthNum(projectid, 9))
							.setRatio(partner.getRate());
					pb.insert();
					return pb;
				})
				.collect(Collectors.toList());

		brokerageList.addAll(subPartnerBrokerageList);
	}

	@Override
	public void recordPartnerAccountFlowAndNotice(PartnerBrokerage partnerBrokerage, String projectname) {
		int partnerType = NumberUtil.safeInt(partnerBrokerage.getPartnerType());
		//生成合伙人账户流水记录
		String partnerTypeName = "";
		if (partnerType == PartnerBrokerageType.BASIC) {
			partnerTypeName = "基本服务费";
		} else if (partnerType == PartnerBrokerageType.PROJECT) {
			partnerTypeName = "项目服务费";
		} else if (partnerType == PartnerBrokerageType.CROWDSOURCE) {
			partnerTypeName = "智众包佣金";
		} else if (partnerType == PartnerBrokerageType.SUB_PARTNER) {
			PartnerDetailDto subPartner = partnerMapper.getPartnerDetail(partnerBrokerage.getSubPartnerid());
			String subPartnerName = subPartner == null ? String.valueOf(partnerBrokerage.getSubPartnerid()) : subPartner.getRealname();
			partnerTypeName = "二级合伙人分佣（" + subPartnerName + "）";
		}

		String flowname = projectname + " " + partnerTypeName;
		new PartnerAccountflow().setPartnerid(partnerBrokerage.getPartnerid())
				.setCompid(partnerBrokerage.getCompid())
				.setUserid(partnerBrokerage.getUserid())
				.setBrokerageid(partnerBrokerage.getBrokerageid())
				.setProjectid(partnerBrokerage.getProjectid())
				.setProjectType(partnerBrokerage.getProjectType())
				.setTradeid(partnerBrokerage.getTradeid())
				.setAmounttype(partnerType)
				.setFlowAmount(partnerBrokerage.getBrokerage())
				.setFlowtype(1)
				.setFlowname(flowname)
				.insert();

		//发送佣金模板消息给合伙人
		wxPartnerMessageService.notifyPartnerBrokerageSettled(partnerBrokerage, projectname);
	}

	@Override
	public BigDecimal sumSettledUnremitCrowdsourceBrokerage(int partnerid) {
		BigDecimal crowdsourceBrokerage = partnerBrokerageMapper.getTotalCrowdsourceBrokerageByPartnerId(partnerid, PartnerBrokerageState.SETTLED);
		BigDecimal crowdCostBrokerage = partnerMonthlyCrowdCostMapper.sumPartnerBrokerage(partnerid, PartnerCrowdsourceCostState.UNSETTLED);
		return crowdsourceBrokerage.add(crowdCostBrokerage);
	}
}
